Skip to content

perf(coverage): stop forking grep per source line in the report phase - #1031

Merged
Chemaclass merged 1 commit into
mainfrom
perf/1005-coverage-report-per-line-grep-forks
Aug 9, 2026
Merged

perf(coverage): stop forking grep per source line in the report phase#1031
Chemaclass merged 1 commit into
mainfrom
perf/1005-coverage-report-per-line-grep-forks

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1005

Profiling --coverage before optimising anything showed the cost is not where the issue assumed. The report phase is ~50-60% of wall time and is identical for both enginesis_executable_line fell back to a grep -E fork for every line it could not classify in pure Bash, and every tracked line is classified twice per run. 286 source lines cost 1055 grep forks.

💡 Changes

  • Replace the combined non-executable regex with case globs, removing the per-line fork. --coverage is 1.6x-2.3x faster (interleaved best-of-5: Bash 5.3 xtrace 3213→1396ms, Bash 3.2 trap 4655→2990ms)
  • Reproduce the old regex exactly, quirks included: inside a POSIX bracket expression a backslash is a literal set member, so [^\)] also excludes \ and [\{\}] also matches a bare line continuation
  • Report the coverage engine under --verbose, and warn when an explicit BASHUNIT_COVERAGE_ENGINE=xtrace cannot be honoured instead of dropping it silently — the common case on macOS's Bash 3.2
  • Guard the budget with a new acceptance test asserting fork count does not grow with source-line count

Verification

Both implementations run over the same 41173 lines across 395 files on Bash 3.2 and 5.3: zero disagreements. The differential harness was mutation-tested — deliberately breaking each rule produced 54 and 4 mismatches respectively, so it discriminates.

Coverage totals unchanged (129/286 trap, 174/286 xtrace) and still match between --parallel and sequential per engine. The two engines differing is documented expected behaviour, not a regression.

Diff coverage from the issue is deliberately not in scope here; filed separately.

Profiling --coverage showed the report, not the capture engine, was half
the wall time and identical for both engines: is_executable_line fell back
to a `grep -E` fork for every line it could not classify in pure Bash, and
every tracked line is classified twice per run (precompute_file_stats, then
report_lcov). 286 source lines cost 1055 grep forks.

The combined regex is replaced by `case` globs reproducing it exactly,
quirks included: inside a POSIX bracket expression a backslash is a literal
member of the set, so `[^\)]` also excludes `\` and `[\{\}]` also matches a
bare line continuation. Verified by running both implementations over the
same 41173 lines across 395 files on Bash 3.2 and 5.3 with zero
disagreements, with the differential harness mutation-tested.

Also surfaces the engine: --verbose reports the one in use, and an explicit
BASHUNIT_COVERAGE_ENGINE=xtrace that the running Bash cannot honour now
warns instead of being dropped silently — the common case on macOS.

Coverage totals are unchanged and still match between --parallel and
sequential for each engine.

Closes #1005
@Chemaclass Chemaclass added the enhancement New feature or request label Aug 9, 2026
@Chemaclass Chemaclass self-assigned this Aug 9, 2026
@Chemaclass
Chemaclass merged commit 7b4713e into main Aug 9, 2026
37 checks passed
@Chemaclass
Chemaclass deleted the perf/1005-coverage-report-per-line-grep-forks branch August 9, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant